package cn.funnymap.lgis.tools.service.metadata.model.geoscene;

import cn.funnymap.lgis.tools.service.metadata.ServiceField;
import cn.funnymap.lgis.tools.service.metadata.ServiceMetadata;
import cn.funnymap.lgis.tools.service.metadata.model.IServiceMetadata;
import cn.funnymap.lgis.tools.util.resttemplate.RestTemplateUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.dom4j.DocumentException;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author jiao xn
 */
public abstract class AbstractGeoSceneService implements IServiceMetadata {
    protected static JSONObject DEFAULT_EXTENT;

    @Resource
    protected RestTemplateUtil restTemplateUtil;

    protected String url;
    protected String restQueryUrl;
    protected String itemInfoQueryUrl;
    protected String metadataQueryUrl;
    protected ServiceMetadata serviceMetadata;

    protected abstract void queryMetadataFromRest();

    protected abstract void queryMetadataFromItemInfo();

    protected abstract void queryMetadataFromMetadata() throws DocumentException;

    static {
        DEFAULT_EXTENT = new JSONObject();
        DEFAULT_EXTENT.put("xmin", -180);
        DEFAULT_EXTENT.put("ymin", -90);
        DEFAULT_EXTENT.put("xmax", 180);
        DEFAULT_EXTENT.put("ymax", 90);
    }

    @Override
    public void initializeUrl(String url) {
        if (StringUtils.hasLength(this.url)) {
            return;
        }

        this.url = url;
        this.restQueryUrl = this.combineServiceRestQueryUrl(url);
        this.itemInfoQueryUrl = this.combineServiceItemInfoQueryUrl(url);
        this.metadataQueryUrl = this.combineMetadataQueryUrl(url);
        this.serviceMetadata = new ServiceMetadata();
        this.serviceMetadata.setUrl(this.url);
    }
    private String combineServiceRestQueryUrl(String url) {
        if (url.contains("?")) {
            return String.format("%s&f=json", url);
        }

        return String.format("%s?f=pjson", url);
    }
    private String combineServiceItemInfoQueryUrl(String url) {
        if (url.contains("?")) {
            url = url.substring(0, url.indexOf("?"));
        }

        return String.format("%s/info/iteminfo?f=json", url);
    }
    private String combineMetadataQueryUrl(String url) {
        if (url.contains("?")) {
            url = url.substring(0, url.indexOf("?"));
        }

        String subLayerRegRule = ".*(/\\d)$";
        Pattern pattern = Pattern.compile(subLayerRegRule);
        Matcher matcher = pattern.matcher(url);
        if (matcher.find()) {
            // 如果当前是子图层，则查询父图层的metadata信息
            url = url.substring(0, url.lastIndexOf(matcher.group(1)));
        }

        return String.format("%s/info/metadata", url);
    }

    @Override
    public ServiceMetadata queryMetadata() {
        try {
            this.queryMetadataFromRest();
            this.queryMetadataFromItemInfo();
            this.queryMetadataFromMetadata();

            return serviceMetadata;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<ServiceField> queryFields() {
        this.queryMetadataFromRest();

        return this.serviceMetadata.getFields();
    }

    protected List<ServiceField> convertFieldsFromJsonArray(JSONArray fields) {
        return fields.stream().map(field -> this.buildFieldInfoDtoFromQueryResult((JSONObject) field)).collect(Collectors.toList());
    }
    private ServiceField buildFieldInfoDtoFromQueryResult(JSONObject fieldJsonObject) {
        ServiceField serviceField = new ServiceField();

        if (fieldJsonObject != null && !fieldJsonObject.isEmpty()) {
            serviceField.setName(fieldJsonObject.getString("name"));
            serviceField.setAlias(fieldJsonObject.getString("alias"));
            serviceField.setType(fieldJsonObject.getString("type"));
            serviceField.setLength(fieldJsonObject.getInteger("length"));
        }

        return serviceField;
    }
}
